package com.hrs.core.service.impl;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.hrs.common.constant.RedisConstants;
import com.hrs.common.constant.RequestUserData;
import com.hrs.common.result.Result;
import com.hrs.core.service.UserLoginLogService;
import com.hrs.core.service.UserService;
import com.hrs.enity.db.User;
import com.hrs.core.mapper.UserMapper;
import com.hrs.enity.db.UserLoginLog;
import com.hrs.enity.dto.UserViewDto;
import com.hrs.enity.ro.LoginFormRo;
import com.hrs.enity.ro.LoginResponseRo;
import com.hrs.enity.ro.UserRegisterRo;
import com.hrs.enity.vo.KaptchaVO;
import com.hrs.third.RedisService;
import com.hrs.util.IPUtil;
import com.hrs.util.RequestUserUtil;
import com.hrs.util.TokenUtil;
import com.hrs.util.VerificationCodeUtil;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
* @author 纱雾休比酱
* @description 针对表【t_user(系统用户表)】的数据库操作Service实现
* @createDate 2022-12-05 23:04:49
*/
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService {

    private static final String VERIFICATION_CODE_REDIS_PREFIX = "vc_%s";

    @Autowired
    private RedisService redisService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserLoginLogService userLoginLogService;
    @Autowired
    private DefaultKaptcha defaultKaptcha;

    /**
     * 用户登录
     * @param loginFormRo
     * @param request
     * @return
     */
    @Override
    public Result<LoginResponseRo> login(LoginFormRo loginFormRo, HttpServletRequest request) {
        LoginResponseRo loginResponseRo = new LoginResponseRo();
        //校验图片验证码
        String vCode = redisService.get(RedisConstants.PICTURE_CODE + loginFormRo.getVCodeUuid());
        if(StringUtils.isBlank(vCode)){
            return Result.error("验证码过期");
        } else if(!vCode.equals(loginFormRo.getVCode())){
            redisService.delete(RedisConstants.PICTURE_CODE + loginFormRo.getVCodeUuid());
            return Result.error("图片验证码错误");
        }
        redisService.delete(RedisConstants.PICTURE_CODE + loginFormRo.getVCodeUuid());

        String account = loginFormRo.getAccount();
        /**
         * 密码进行md5加密
         */
        String password = loginFormRo.getPassword();

        //方式一：手机验证码
        if(StringUtils.isBlank(password)){
            String pCode = redisService.get(RedisConstants.PHONE_CODE + loginFormRo.getAccount());
            if(StringUtils.isBlank(pCode) || !pCode.equals(loginFormRo.getPCode())){
                return Result.error("手机验证码错误");
            }

            loginResponseRo = userMapper.login(account, null);

            if(Objects.isNull(loginResponseRo)){
                return Result.error("账号不存在");
            }
        } else {
            password = DigestUtils.md5DigestAsHex(loginFormRo.getPassword().getBytes());
            //方式二：手机号 + 密码
            loginResponseRo  = userMapper.login(account, password);
        }

        if (Objects.isNull(loginResponseRo)) {
            return Result.error("账号不存在或密码错误");
        }
        if (loginResponseRo.getIsDisabled() == 1) {
            return Result.error("账户被禁用");
        }

        //jwt token赋值
        String compactJws = TokenUtil.generateToken(loginResponseRo);

        //根据id保存用户的一些信息到redis
        RequestUserData requestUserData = new RequestUserData();
        BeanUtils.copyProperties(loginResponseRo,requestUserData);
        try {
            redisService.set(RedisConstants.LOGIN_USER_REQUEST_DATA + loginResponseRo.getId(),
                    requestUserData,
                    RedisConstants.USER_REQUEST_DATA_TTL_DAY,
                    TimeUnit.DAYS);
        } catch (Exception e){
            return Result.error("登录失败，请重试");
        }

        loginResponseRo.setToken(compactJws);

        //登陆操作日志
        UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
        UserLoginLog userLoginLog =
                UserLoginLog.builder()
                        .uid(loginResponseRo.getId())
                        .username(loginResponseRo.getActualName())
                        .remoteIp(IPUtil.getRemoteIp(request))
                        .remotePort(request.getRemotePort())
                        .remoteBrowser(userAgent.getBrowser().getName())
                        .remoteOs(userAgent.getOperatingSystem().getName())
                        .loginStatus(1).build();
        try {
            userLoginLogService.save(userLoginLog);
        } catch (Exception e){
            return Result.error("登录失败，请重试");
        }

        return Result.success(loginResponseRo);
    }

    /**
     * 发送图片验证码
     * @return
     */
    @Override
    public Result<KaptchaVO> sendImgCode() {
        KaptchaVO kaptchaVO = new KaptchaVO();
        String uuid = buildVerificationCodeRedisKey(UUID.randomUUID().toString());
        String kaptchaText = defaultKaptcha.createText();

        String base64Code = "";

        BufferedImage image = defaultKaptcha.createImage(kaptchaText);
        ByteArrayOutputStream outputStream = null;
        try {
            outputStream = new ByteArrayOutputStream();
            ImageIO.write(image, "jpg", outputStream);
            base64Code = Base64.encodeBase64String(outputStream.toByteArray());
        } catch (Exception e) {
            log.error("verificationCode exception .{}", e);
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (Exception e) {
                    log.error("verificationCode outputStream close exception .{}", e);
                }
            }
        }
        kaptchaVO.setUuid(uuid);
        kaptchaVO.setCode("data:image/png;base64," + base64Code);
        redisService.set(RedisConstants.PICTURE_CODE + uuid,kaptchaText,RedisConstants.CACHE_IMG_CODE_TTL,TimeUnit.MINUTES);
        return Result.success(kaptchaVO);
    }

    /**
     * 退出登录
     * @return
     */
    @Override
    public Result<String> loginOut() {
        String key = RedisConstants.LOGIN_USER_REQUEST_DATA + RequestUserUtil.getRequestUserId();
        redisService.delete(RedisConstants.LOGIN_USER_REQUEST_DATA + RequestUserUtil.getRequestUserId());
        return Result.success();
    }

    /**
     * 发送搜集验证码
     * @return
     */
    @Override
    public Result<String> sendPhoneCode(String phone) {
        Integer phoneCode = VerificationCodeUtil.getVerificationCode(6);
        redisService.set(RedisConstants.PHONE_CODE + phone,phoneCode,5,TimeUnit.MINUTES);
        return Result.success("手机验证码为：" + phoneCode + "，五分钟内有效！");
    }

    private String buildVerificationCodeRedisKey(String uuid) {
        return String.format(VERIFICATION_CODE_REDIS_PREFIX, uuid);
    }

    @Override
    public Result<String> register(UserRegisterRo userRegisterRo) {
        User user = new User();
        BeanUtils.copyProperties(userRegisterRo,user);
        user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
        this.save(user);
        return Result.success("注册成功");
    }

    @Override
    public Result<List<UserViewDto>> listUser(Integer roleId) {
        List<UserViewDto> userViewDtos = userMapper.listUser(roleId, 0);
        return Result.success(userViewDtos);
    }
}




